using System.Windows.Input;
using ScreenToGif.Util;

namespace ScreenToGif.Native.Helpers;

public class HotKeyCollection : IDisposable
{
    public static readonly HotKeyCollection Default = new();

    internal List<HotKey> HotKeys { get; } = new();

    /// <summary>
    /// Registers the given keyboard shortcut with a given callback.
    /// </summary>
    /// <param name="modifier">The modifier of the keyboard command.</param>
    /// <param name="key">The key of the keyboard command.</param>
    /// <param name="windowsHandle">A handle to the window that will receive WM_HOTKEY messages generated by the hot key.</param>
    /// <param name="callback">The callback that will be invoked when the keyboard command is pressed.</param>
    /// <exception cref="InvalidOperationException">If the key is already in use.</exception>
    internal void RegisterHotKey(ModifierKeys modifier, Key key, IntPtr windowsHandle, Action callback)
    {
        if (key == Key.None)
            return;

        HotKeys.Add(new HotKey(modifier, key, windowsHandle, callback));
    }

    /// <summary>
    /// Registers the given keyboard shortcut with a given callback.
    /// </summary>
    /// <param name="modifier">The modifier of the keyboard command.</param>
    /// <param name="key">The key of the keyboard command.</param>
    /// <param name="callback">The callback that will be invoked when the keyboard command is pressed.</param>
    /// <param name="unregisterFirst">Tries to unregister first, before trying to register the hotkey.</param>
    /// <exception cref="InvalidOperationException">If the key is already in use.</exception>
    internal void RegisterHotKey(ModifierKeys modifier, Key key, Action callback, bool unregisterFirst = false)
    {
        if (key == Key.None)
            return;

        HotKeys.Add(new HotKey(modifier, key, callback, unregisterFirst));
    }

    /// <summary>
    /// Tries to register the given keyboard shortcut with a given callback.
    /// </summary>
    /// <param name="modifier">The modifier of the keyboard command.</param>
    /// <param name="key">The key of the keyboard command.</param>
    /// <param name="callback">The callback that will be invoked when the keyboard command is pressed.</param>
    /// <param name="unregisterFirst">Tries to unregister first, before trying to register the hotkey.</param>
    /// <exception cref="InvalidOperationException">If the key is already in use.</exception>
    public bool TryRegisterHotKey(ModifierKeys modifier, Key key, Action callback, bool unregisterFirst = false)
    {
        if (key == Key.None)
            return true;

        try
        {
            HotKeys.Add(new HotKey(modifier, key, callback, unregisterFirst));
            return true;
        }
        catch (Exception ex)
        {
            LogWriter.Log(ex, "Key already registered: " + key);
            return false;
        }
    }

    public void Remove(ModifierKeys modifier, Key key)
    {
        var hot = Default.HotKeys.FirstOrDefault(f => f.Key == key && f.Modifier == modifier);
        hot?.Dispose();

        if (hot != null)
            Default.HotKeys.Remove(hot);
    }

    public void Dispose()
    {
        foreach (var hotKey in HotKeys)
            hotKey.Dispose();
    }
}